#include "console.h"
#include "sbi.h"
#include "type.h"
#include "mmu.h"
#include "stdio.h"
#include "proc.h"
#include "string.h"

struct {
    spinlock_t lk;
    // semaphore_t lk;
    byte_t buf[BUFSIZE];
    uint32_t read;
    uint32_t write;
} console;

void
console_init(void) {
    spinlock_init(&console.lk, "console_lk");
    console.read = 0;
    console.write = 0;
}
void
console_putc(int ch) {
    if (ch == BACKSPACE) {
        sbi_putchar('\b');
        sbi_putchar(' ');
        sbi_putchar('\b');
    } else {
        sbi_putchar(ch);
    }
}

void
console_write(void* src, uint32_t IsUser, size_t size)  // size: byte
{
// #ifdef DEBUG
//     printf("console_write: src = %p, IsUser = %d, size = %d\n", src, IsUser, size);
// #endif
    spinlock_acquire(&console.lk);
    if (IsUser) {
        for(size_t i = 0; i < size; i++)
        {
            sbi_putchar(((char*)src)[i]);
        }
    } else {
        for (size_t i = 0; i < size; i++) {
            sbi_putchar(((char*)src)[i]);
        }
    }
    spinlock_release(&console.lk);
}

void
console_read(void* dst, uint32_t IsUser, size_t size) {
    panic("console_read");
    byte_t ch;
    spinlock_acquire(&console.lk);
    while (size > 0) {
        while (console.read == console.write) {
            sleep_spin(&console.read, &console.lk);
        }
        ch = console.buf[console.read % BUFSIZE];
        console.read++;
        if (IsUser) {
            printf("IsUser");
            while (1)
                ;
        } else {
            memmove(dst, &ch, 1);
        }
        dst++;
        size--;
        if (ch == '\n')
            break;
    }
    spinlock_release(&console.lk);
}

void
console_intr(int ch) {
    spinlock_acquire(&console.lk);
    console_putc(ch);
    if ((console.write - console.read) >= BUFSIZE) {
        panic("console buf full");
        while (1)
            ;
    }
    console.buf[console.write % BUFSIZE] = ch;
    console.write++;
    if ((ch == '\n') || (console.write == console.read + BUFSIZE)) {
        proc_wakeupSpin(&console.read);  // TODO
    }
    spinlock_release(&console.lk);
}
